package main

import (
	"fmt"
	"gopkg.in/yaml.v3"
	"log"
	"net"
	"net/http"
	"os"
	"proxyRelayServer/src/client"
	"proxyRelayServer/src/server"
	"runtime"
	"strings"
)

type Config struct {
	Broker struct {
		Enable bool
		// broker 为外部提供服务的地址
		ListenAddr string `yaml:"listenAddr"`
		// broker 为客户端提供的订阅地址
		SubAddr  string `yaml:"subAddr"`
		WhiteReg string `yaml:"whiteReg"`
		Password string `yaml:"password"`
	}
	Client struct {
		Enable bool
		// broker的订阅地址
		SubAddr string `yaml:"subAddr"`
		// 客户端的服务地址
		ServiceAddr string `yaml:"serviceAddr"`
		WhiteReg    string `yaml:"whiteReg"`
		Password    string `yaml:"password"`
		//与 broker间的最大连接数
		ConnCoreSize int `yaml:"connCoreSize"`
	}
}

func readConfig() Config {
	file, err := os.ReadFile("./config.yml")
	if err != nil {
		panic(err)
	}
	var config Config
	err = yaml.Unmarshal(file, &config)
	if err != nil {
		panic(err)
	}
	log.Printf("%+v", config)
	return config
}

func logger() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	//file, err := os.OpenFile(fmt.Sprintf("%s.log", time.Now().Format("2006-01-02")), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	//if err != nil {
	//	panic(err)
	//}
	//log.SetOutput(file)
}

var relayBroker *server.RelayBroker

func main() {
	logger()
	config := readConfig()
	go func() {
		tryStartBroker(config)
	}()
	go func() {
		tryStartClient(config)
	}()
	if config.Broker.Password == "" {
		config.Broker.Password = "xxsbs"
	}
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		get := request.URL.Query().Get("pw")
		if get == config.Broker.Password {
			idx := strings.LastIndexAny(request.RemoteAddr, ":")
			if idx != -1 {
				relayBroker.Lock.Lock()
				defer relayBroker.Lock.Unlock()
				before := request.RemoteAddr[:idx]
				relayBroker.WhiteList[before] = struct{}{}
				log.Printf("%s 加入白名单", before)
			}
		}
	})
	if config.Broker.WhiteReg == "" {
		config.Broker.WhiteReg = ":36666"
	}
	panic(http.ListenAndServe(config.Broker.WhiteReg, nil))
}

func tryStartBroker(c Config) {
	if !c.Broker.Enable {
		return
	}
	broker := c.Broker
	if broker.ListenAddr != "" && broker.ListenAddr == broker.SubAddr {
		panic(fmt.Errorf("listenAddr 与 SubAddr不能为同一地址"))
	}
	listenAddr, err := net.ResolveTCPAddr("tcp", broker.ListenAddr)
	if err != nil {
		panic(err)
	}
	subAddr, err := net.ResolveTCPAddr("tcp", broker.SubAddr)
	if err != nil {
		panic(err)
	}
	relayBroker = server.NewRelayBroker(listenAddr, subAddr)
	panic(relayBroker.Listen())
}

func tryStartClient(c Config) {
	if !c.Client.Enable {
		return
	}
	clientConfig := c.Client
	if clientConfig.ConnCoreSize == 0 {
		clientConfig.ConnCoreSize = runtime.NumCPU() * 2
	}
	if clientConfig.SubAddr != "" && clientConfig.ServiceAddr == clientConfig.SubAddr {
		panic(fmt.Errorf("serviceAddr 与 subAddr不能为同一地址"))
	}
	before, _, found := strings.Cut(clientConfig.SubAddr, ":")
	if !found {
		panic(fmt.Errorf("subAddr 需要是 ip:port 格式"))
	}
	//注册白名单
	_, err2 := http.Get("http://" + before + clientConfig.WhiteReg + "?pw=" + clientConfig.Password)
	if err2 != nil {
		panic(err2)
	}
	subAddr, err := net.ResolveTCPAddr("tcp", clientConfig.SubAddr)
	if err != nil {
		panic(err)
	}
	serviceAddr, err := net.ResolveTCPAddr("tcp", clientConfig.ServiceAddr)
	if err != nil {
		panic(err)
	}
	subscriber := client.NewSubscriber(subAddr, serviceAddr, clientConfig.ConnCoreSize)
	subscriber.Start()
}
